﻿namespace CommonHelper
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using CommonHelper.Internal;

    public static class StringExtensions
    {
        private static readonly Random rand = new Random((int)DateTime.Now.Ticks);

        public static bool IsNullOrEmpty(this string input)
        {
            return input == null || input.Length == 0;
        }

        public static bool IsNullOrWhiteSpace(this string input)
        {
            if (input == null || input.Length == 0)
                return true;

            for (int i = 0; i < input.Length; i++)
            {
                if (!char.IsWhiteSpace(input[i]))
                    return false;
            }

            return true;
        }

        #region Format
        public static string Format(this string format, params object[] args)
        {
            return string.Format(format, args);
        }

        public static string Format(this string format, object arg0)
        {
            return string.Format(format, arg0);
        }

        public static string Format(this string format, object arg0, object arg1)
        {
            return string.Format(format, arg0, arg1);
        }

        public static string Format(this string format, object arg0, object arg1, object arg2)
        {
            return string.Format(format, arg0, arg1, arg2);
        }

        #endregion

        public static string GenerateRandomString(this string input, int count)
        {
            if (input.IsNullOrEmpty() || count <= 0) return null;

            StringBuilder builder = new StringBuilder(count + 1);
            for (int i = 0; i < count; i++)
            {
                builder.Append(input[rand.Next(input.Length)]);
            }

            return builder.ToString();
        }

        #region Sample Converter
        public static int ToInt32(this string input)
        {
            return int.Parse(input);
        }

        public static bool TryToInt32(this string input, out int result)
        {
            return int.TryParse(input, out result);
        }

        public static uint ToUInt32(this string input)
        {
            return uint.Parse(input);
        }

        public static bool TryToUInt32(this string input, out uint result)
        {
            return uint.TryParse(input, out result);
        }

        public static long ToInt64(this string input)
        {
            return long.Parse(input);
        }

        public static bool TryToInt64(this string input, out long result)
        {
            return long.TryParse(input, out result);
        }

        public static ulong ToUInt64(this string input)
        {
            return ulong.Parse(input);
        }

        public static bool TryToInt32(this string input, out ulong result)
        {
            return ulong.TryParse(input, out result);
        }

        public static double ToDouble(this string input)
        {
            return double.Parse(input);
        }

        public static bool TryToDouble(this string input, out double result)
        {
            return double.TryParse(input, out result);
        }

        public static decimal ToDecimal(this string input)
        {
            return decimal.Parse(input);
        }

        public static bool TryToDecimal(this string input, out decimal result)
        {
            return decimal.TryParse(input, out result);
        }

        public static DateTime ToDateTime(this string input)
        {
            return DateTime.Parse(input);
        }

        public static bool TryToDateTime(this string input, out DateTime result)
        {
            return DateTime.TryParse(input, out result);
        }

        public static bool ToBoolean(this string input)
        {
            return bool.Parse(input);
        }

        public static bool TryToBoolean(this string input, out bool result)
        {
            return bool.TryParse(input, out result);
        }

        public static Guid ToGuid(this string input)
        {
            return Guid.Parse(input);
        }

        public static bool TryToGuid(this string input, out Guid result)
        {
            return Guid.TryParse(input, out result);
        }

        public static byte[] ToBytes(this string input, Encoding encoder = null)
        {
            if (encoder == null)
                encoder = Encoding.UTF8;
            return encoder.GetBytes(input);
        }

        public static byte[] ToBytes(this string input, string encoder = "utf-8")
        {
            return Encoding.GetEncoding(encoder).GetBytes(input);
        }
        #endregion

        #region Match
        public static bool IsMatch(this string input, string pattern)
        {
            return IsMatch(input, new Regex(pattern));
        }

        public static bool IsMatch(this string input, Regex regex)
        {
            return regex.IsMatch(input);
        }

        public static bool MatchTo(this string pattern, string input)
        {
            return Regex.IsMatch(input, pattern);
        }
        #endregion

        #region Pinyin
        /// <summary>
        /// 取中文文本的拼音首字母
        /// </summary>
        /// <param name="text">编码为UTF8的文本</param>
        /// <returns>返回中文对应的拼音首字母</returns>
        public static string GetInitials(this string text)
        {
            text = text.Trim();
            StringBuilder chars = new StringBuilder();
            for (var i = 0; i < text.Length; ++i)
            {
                string py = GetPinyin(text[i]);
                if (py != "") chars.Append(py[0]);
            }

            return chars.ToString().ToUpper();
        }

        /// <summary>
        /// 取中文文本的拼音首字母
        /// </summary>
        /// <param name="text">文本</param>
        /// <param name="encoding">源文本的编码</param>
        /// <returns>返回encoding编码类型中文对应的拼音首字母</returns>
        public static string GetInitials(this string text, Encoding encoding)
        {
            string temp = ConvertEncoding(text, encoding, Encoding.UTF8);
            return ConvertEncoding(GetInitials(temp), Encoding.UTF8, encoding);
        }

        /// <summary>
        /// 取中文文本的拼音
        /// </summary>
        /// <param name="text">编码为UTF8的文本</param>
        /// <returns>返回中文文本的拼音</returns>
        public static string GetPinyin(this string text)
        {
            StringBuilder sbPinyin = new StringBuilder();
            for (var i = 0; i < text.Length; ++i)
            {
                string py = GetPinyin(text[i]);
                if (py != "") sbPinyin.Append(py);
                sbPinyin.Append(" ");
            }

            return sbPinyin.ToString().Trim();
        }

        /// <summary>
        /// 取中文文本的拼音
        /// </summary>
        /// <param name="text">编码为UTF8的文本</param>
        /// <param name="encoding">源文本的编码</param>
        /// <returns>返回encoding编码类型的中文文本的拼音</returns>
        public static string GetPinyin(this string text, Encoding encoding)
        {
            string temp = ConvertEncoding(text.Trim(), encoding, Encoding.UTF8);
            return ConvertEncoding(GetPinyin(temp), Encoding.UTF8, encoding);
        }

        /// <summary>
        /// 取和拼音相同的汉字列表
        /// </summary>
        /// <param name="Pinyin">编码为UTF8的拼音</param>
        /// <returns>取拼音相同的汉字列表，如拼音“ai”将会返回“唉爱……”等</returns>
        public static string GetChineseText(this string pinyin)
        {
            string key = pinyin.Trim().ToLower();

            foreach (string str in PyCode.codes)
            {
                if (str.StartsWith(key + " ") || str.StartsWith(key + ":"))
                    return str.Substring(7);
            }

            return "";
        }

        /// <summary>
        /// 取和拼音相同的汉字列表，编码同参数encoding
        /// </summary>
        /// <param name="Pinyin">编码为encoding的拼音</param>
        /// <param name="encoding">编码</param>
        /// <returns>返回编码为encoding的拼音为pinyin的汉字列表，如拼音“ai”将会返回“唉爱……”等</returns>
        public static string GetChineseText(string pinyin, Encoding encoding)
        {
            string text = ConvertEncoding(pinyin, encoding, Encoding.UTF8);
            return ConvertEncoding(GetChineseText(text), Encoding.UTF8, encoding);
        }

        /// <summary>
        /// 返回单个字符的汉字拼音
        /// </summary>
        /// <param name="ch">编码为UTF8的中文字符</param>
        /// <returns>ch对应的拼音</returns>
        public static string GetPinyin(this char ch)
        {
            short hash = GetHashIndex(ch);
            for (var i = 0; i < PyHash.hashes[hash].Length; ++i)
            {
                short index = PyHash.hashes[hash][i];
                var pos = PyCode.codes[index].IndexOf(ch, 7);
                if (pos != -1)
                    return PyCode.codes[index].Substring(0, 6).Trim();
            }
            return ch.ToString();
        }

        /// <summary>
        /// 返回单个字符的汉字拼音
        /// </summary>
        /// <param name="ch">编码为encoding的中文字符</param>
        /// <returns>编码为encoding的ch对应的拼音</returns>
        public static string GetPinyin(this char ch, Encoding encoding)
        {
            ch = ConvertEncoding(ch.ToString(), encoding, Encoding.UTF8)[0];
            return ConvertEncoding(GetPinyin(ch), Encoding.UTF8, encoding);
        }

        /// <summary>
        /// 转换编码 
        /// </summary>
        /// <param name="text">文本</param>
        /// <param name="srcEncoding">源编码</param>
        /// <param name="dstEncoding">目标编码</param>
        /// <returns>目标编码文本</returns>
        public static string ConvertEncoding(this string text, Encoding srcEncoding, Encoding dstEncoding)
        {
            byte[] srcBytes = srcEncoding.GetBytes(text);
            byte[] dstBytes = Encoding.Convert(srcEncoding, dstEncoding, srcBytes);
            return dstEncoding.GetString(dstBytes);
        }

        /// <summary>
        /// 取文本索引值
        /// </summary>
        /// <param name="ch">字符</param>
        /// <returns>文本索引值</returns>
        private static short GetHashIndex(char ch)
        {
            return (short)((uint)ch % PyCode.codes.Length);
        }
        #endregion

        public static string Join(this IEnumerable<string> values, string separator)
        {
            if (separator == null) separator = string.Empty;
            StringBuilder builder = new StringBuilder(values.Count() * (20 + separator.Length));
            foreach (var value in values)
            {
                builder.Append(value);
                builder.Append(separator);
            }

            return builder.ToString();
        }

        public static string Join(this string[] values, string separator)
        {
            return string.Join(separator, values);
        }

        public static string Join(this IEnumerable<string> values, char separator)
        {
            StringBuilder builder = new StringBuilder(values.Count() * 21);
            foreach (var value in values)
            {
                builder.Append(value);
                builder.Append(separator);
            }

            return builder.ToString();
        }

        public static string Join(this string[] values, char separator)
        {
            return string.Join(new string(separator, 1), values);
        }

        public static bool IsEnglish(this string input)
        {
            char ch;
            for (int i = 0; i < input.Length; ++i)
            {
                ch = input[i];
                if (ch < 'A' || ch > 'z' || (ch > 'Z' && ch < 'a'))
                    return false;
            }

            return true;
        }

        public static bool IsEnglish(this char input)
        {
            return input >= 'a' && input <= 'z' ||
                   input >= 'A' && input <= 'Z';
        }
    }
}